/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrn.dimap.Grafo;

import br.ufrn.dimap.Grafo.excecoes.*;
import br.ufrn.dimap.Visitors.Visitor;
import java.awt.Color;
import java.io.Serializable;
import java.util.*;

/**
 *
 * @author Anthonini
 */

public class GrafoLista extends Rede implements Element  {
    static final long serialVersionUID = -8134418438354408967L;
    private LinkedList<Usuario> listaVertices;
    private LinkedList<LinkedList<Relacao>> listaDeAdjacencias;
    private Usuario raiz;
    
    public GrafoLista() {
        listaVertices = new LinkedList();
        listaDeAdjacencias = new LinkedList();
    }

    public Usuario buscarUsuarioPorID(String id) {
        Usuario retorno = null;
        for (int i = 0; i < listaVertices.size(); i++) {
            if (id.equals(listaVertices.get(i).getId())) {
                retorno = listaVertices.get(i);
            }
        }
        return retorno;
    }
    
    public Usuario buscarUsuarioPorNome(String nome) {
        Usuario retorno = null;
        for (int i = 0; i < listaVertices.size(); i++) {
            if (nome.equals(listaVertices.get(i).getNome())) {
                retorno = listaVertices.get(i);
            }
        }
        return retorno;
    }
    
    public int buscarPosicaoUsuario(String id) {
        int retorno = -1;
        for (int i = 0; i < listaVertices.size(); i++) {
            if (id.equals(listaVertices.get(i).getId())) {
                retorno = i;
            }
        }
        return retorno;
    }

    public boolean existeUsuario(String id) {
        return (buscarUsuarioPorID(id) != null);
    }

    public void inserirUsuario(Usuario vertice) {
        if (!existeUsuario(vertice.getId())) {
            listaVertices.add(vertice);
            listaDeAdjacencias.add(new LinkedList());
        } else {
            
        }
    }

    private boolean existeRelacao(Usuario u1, Usuario u2){
        Iterator<Usuario> usuarioIt = this.obterListaAdjacencia(u1);
        while(usuarioIt.hasNext()){
            //System.out.println(u1.getNome()+"->"+u2.getNome());
            if(u2.getId().equals(usuarioIt.next().getId())){
                return true;
            }
        }
        usuarioIt = this.obterListaAdjacencia(u2);
        while(usuarioIt.hasNext()){
            //System.out.println(u1.getNome()+"->"+u2.getNome());
            if(u1.getId().equals(usuarioIt.next().getId())){
                return true;
            }
        }
        return false;
    }
    public void inserirRelacao(Relacao aresta) throws ParDeUsuariosNaoExisteException {
        int posicaoOrigem = buscarPosicaoUsuario(aresta.getOrigem().getId());
        int posicaoDestino = buscarPosicaoUsuario(aresta.getDestino().getId());
        if (posicaoOrigem != -1 && posicaoDestino != -1) {
            if(!existeRelacao(aresta.getOrigem(), aresta.getDestino())){
                listaDeAdjacencias.get(posicaoOrigem).add(aresta);
                listaDeAdjacencias.get(posicaoDestino).add(new Relacao(aresta.getDestino(), aresta.getOrigem()));
            }
        } else {
            throw new ParDeUsuariosNaoExisteException();
        }
    }

    public Relacao removerRelacao(String origem, String destino) throws ParDeUsuariosNaoExisteException {
        Relacao retorno = null;
        int posicaoOrigem = buscarPosicaoUsuario(origem);
        int posicaoDestino = buscarPosicaoUsuario(destino);
        Iterator<Relacao> arestaIterador = listaDeAdjacencias.get(posicaoOrigem).iterator();
        Relacao arestaAux;
        if (posicaoOrigem != -1 && posicaoDestino != -1) {
            while (arestaIterador.hasNext() && retorno == null) {
                arestaAux = arestaIterador.next();
                if (arestaAux.getDestino().getNome().equals(destino)) {
                    listaDeAdjacencias.get(posicaoOrigem).remove(arestaAux);
                    retorno = arestaAux;
                }
            }
        } else {
            throw new ParDeUsuariosNaoExisteException();
        }
        return retorno;
    }

    public Usuario removerUsuario(String nome) throws UsuarioNaoExistenteException {
        Usuario retorno = null;
        int posicaoVertice = buscarPosicaoUsuario(nome);
        if (posicaoVertice != -1) {
            listaVertices.remove(posicaoVertice);
            listaDeAdjacencias.remove(posicaoVertice);
        } else {
            throw new UsuarioNaoExistenteException(nome);
        }
        return retorno;
    }

    public Iterator<Relacao> obterRelacoes() {
        LinkedList<Relacao> arestas = new LinkedList();
        Iterator<Relacao> arestasIterador;
        for (int i = 0; i < listaVertices.size(); i++) {
            arestasIterador = listaDeAdjacencias.get(i).iterator();
            while (arestasIterador.hasNext()) {
                arestas.add(arestasIterador.next());
            }
        }
        return arestas.iterator();
    }
    
    public Iterator<Usuario> obterListaAdjacencia(Usuario u) {
        LinkedList<Usuario> listaAdj = new LinkedList();

        Iterator<Relacao> arestasIterador;
        for (int i = 0; i < listaVertices.size(); i++) {
            arestasIterador = listaDeAdjacencias.get(i).iterator();
            while (arestasIterador.hasNext()) {
                Relacao r = arestasIterador.next();
                if(r.getOrigem().getId().equals(u.getId()))
                    listaAdj.add(r.getDestino());
            }
        }
        return listaAdj.iterator();
    }
    
    

    @Override
    public void accept(Visitor v) {
        /*for (int i = 0; i < listaVertices.size(); i++) {
            v.visit(listaVertices.get(i));
        }*/
        v.setGrafo(this);
        LinkedList<Relacao> arestas = new LinkedList();
        List<Usuario> amigos = new ArrayList<Usuario>();
        arestas = listaDeAdjacencias.get(buscarPosicaoUsuario(raiz.getId()));
        Iterator<Relacao> arestasIterator = arestas.iterator();   
        while (arestasIterator.hasNext()) {
            Relacao a = arestasIterator.next();
            if(amigos.isEmpty() || !amigos.get(0).getId().equals(a.getDestino().getId())){
                v.visit(a.getDestino());
            }else{
                break;
            }
        }
    }
    
    public Usuario atualizarUsuario(Usuario usuario) {
        Usuario retorno = null;
        for (int i = 0; i < listaVertices.size(); i++) {
            if (usuario.getId().equals(listaVertices.get(i).getId())) {
                listaVertices.get(i).setAniversario(usuario.getAniversaio());
                listaVertices.get(i).setDescricao(usuario.getDescricao());
                listaVertices.get(i).setEmail(usuario.getEmail());
                listaVertices.get(i).setGenero(usuario.getGenero());
                listaVertices.get(i).setLocal(usuario.getLocal());
                listaVertices.get(i).setPosts(usuario.getPosts());
                listaVertices.get(i).setTemInfo(true);
            }
        }
        return retorno;
    }
    
    public Usuario getRaiz() {
        return raiz;
    }

    public void setRaiz(Usuario raiz) {
        this.raiz = raiz;
    }
    
    //Pega so as informacoes basicas
    public List<Usuario> getAmigosLista(Usuario usuario){
        LinkedList<Relacao> arestas = new LinkedList();
        List<Usuario> amigos = new ArrayList<Usuario>();
        System.out.println(usuario.getId());
        System.out.println(buscarPosicaoUsuario(usuario.getId()));
        arestas = listaDeAdjacencias.get(buscarPosicaoUsuario(usuario.getId()));
        //amigos = new String[arestas.size()][2];
        Iterator<Relacao> arestasIterator = arestas.iterator();   
        int i = 0;
        while (arestasIterator.hasNext()) {
            Relacao a = arestasIterator.next();
            amigos.add(new Usuario(a.getDestino().getId(), a.getDestino().getNome()));
            System.out.println(a.getOrigem().getNome()+"->"+a.getDestino().getNome());
        }
        return amigos;
    }
    
    public void accept(Usuario usuario, Visitor v){
        v.setGrafo(this);
        LinkedList<Relacao> arestas = new LinkedList();
        List<Usuario> amigos = new ArrayList<Usuario>();
        arestas = listaDeAdjacencias.get(buscarPosicaoUsuario(usuario.getId()));
        Iterator<Relacao> arestasIterator = arestas.iterator();   
        while (arestasIterator.hasNext()) {
            Relacao a = arestasIterator.next();
            if(amigos.isEmpty() || !amigos.get(0).getId().equals(a.getDestino().getId())){
                amigos.add(new Usuario(a.getDestino().getId(), a.getDestino().getNome()));
                v.visit(usuario);
            }else{
                break;
            }
        }
        //return amigos;
    }
    private void buscaEmProfundidadeAux (int i, boolean visitado[], List<Usuario> visitados, Visitor v)
    {	
        try{
            v.visit(listaVertices.get(i));
            visitados.add(listaVertices.get(i));
            visitado[i] = true;
            Iterator iter = listaDeAdjacencias.get(i).iterator();
            Usuario u;
            while (iter.hasNext())
            {
                    u = ((Relacao) iter.next()).getDestino();
                    int indice = buscarPosicaoUsuario(u.getId());
                    if (!visitado[indice])
                            buscaEmProfundidadeAux (indice, visitado, visitados, v);
            }
        }catch(Exception e){
            
        }
    }
    
    public List<Usuario> buscaEmProfundidade(int raiz, Visitor v){
        List<Usuario> visitados = new ArrayList<Usuario>();
        boolean visitado[] = new boolean[this.listaVertices.size()];
        buscaEmProfundidadeAux(raiz, visitado, visitados, v);
        return visitados;
    }
    
    public List<Usuario> buscaEmLargura(int raiz, Visitor v){
        boolean enfileirado[] = new boolean[listaVertices.size()];
        List<Usuario> visitados = new ArrayList<Usuario>();
        Queue<Usuario> fila = new LinkedList<Usuario>();
        try{
            enfileirado[raiz] = true;
            fila.add(listaVertices.get(raiz));
        }catch(Exception e){
        
        }
        Usuario u;
        int indice;
        while(!fila.isEmpty())
        {
        	u = fila.remove();
        	indice = buscarPosicaoUsuario(u.getId());
   
                v.visit(u);
                visitados.add(u);
                System.out.println(u.getNome());
        	Iterator<Relacao> sucessores = listaDeAdjacencias.get(indice).iterator();
        	Usuario prox;
        	while(sucessores.hasNext())
        	{
        		prox = sucessores.next().getDestino();
                        
        		indice = buscarPosicaoUsuario(prox.getId());
        		if (!enfileirado[indice])
        		{
        			enfileirado[indice] = true;
        			fila.add(prox);
        		}
        	}
        }
        return visitados;
    }
    
    public boolean existeInfo(String id){
        if(buscarUsuarioPorID(id).getPosts() == null){
            return false;
        }
        return true;
    }
}